<?php
// E:\qh\cygwin64_php_mini\bin\php.exe E:\qh\speed\swoole.php

error_reporting(0);

use Swoole\Http\Response as Rep;
use Swoole\Http\Request as Req;
use Swoole\Http\Server;

define('APP_DIR', realpath('./'));
define('APP_EVN', 'swoole');
define('APP_PORT', 10086);

/**
 * swoole启动
 *
 * Class swoole
 */
class swoole
{
    /** @var Server $http */
    public $http;
    public $queue;
    public $globals;
    public $port = 9999;
    public $setting = array();

    /**
     * 配置
     * @param $setting
     */
    public function setting($setting)
    {
        $this->setting = $setting;
    }

    /**
     * 配置
     * @param $port
     */
    public function setPort($port)
    {
        $this->port = $port;
    }

    /**
     * 启动
     */
    function start()
    {
        echo "
     _______   ______   ___   ___    .______     ______     ______   .___________.
    |   ____| /  __  \  \  \ /  /    |   _  \   /  __  \   /  __  \  |           |
    |  |__   |  |  |  |  \  V  /     |  |_)  | |  |  |  | |  |  |  | `---|  |----`
    |   __|  |  |  |  |   >   <      |   _  <  |  |  |  | |  |  |  |     |  |     
    |  |     |  `--'  |  /  .  \     |  |_)  | |  `--'  | |  `--'  |     |  |     
    |__|      \______/  /__/ \__\    |______/   \______/   \______/      |__|    
                                                                               
                :: Fox Boot V1.1 ::        (swoole:" . swoole_version() . ")\n";
        echo "open web http://foxboot.v.cnbbx.com:{$this->port}/\n";
        $this->http = new Server("0.0.0.0", $this->port);
        $this->http->set($this->setting);
        $this->http->on('workerStart', array($this, 'onWorkerStart'));
        $this->http->on('request', array($this, 'onRequest'));
        $this->http->start();
    }

    /**
     * @param $server
     * @param $worker_id
     */
    function onWorkerStart($server, $worker_id)
    {
        global $GLOBALS;
        require(APP_DIR . '/lib/core.php');
        logs("onWorkerStart workerId : [{$worker_id}]");
        if ($this->globals == null) {
            $this->globals = true;
            $_SERVER["HTTP_HOST"] = "app.v.cnbbx.com";
            $GLOBALS += require(APP_DIR . '/config.php');
        }
    }

    /**
     * @param Req $request
     * @param Rep $response
     * @return mixed|void
     */
    function onRequest($request, $response)
    {
        global $GLOBALS, $app, $mimeTypeMap;
        $app = new Core();
        $app->response = $response;
        $ret = [];
        $ret += !$request->get ? [] : $request->get;
        $ret += !$request->post ? [] : $request->post;
        $app->request = $ret;
        $app->server = $request->server;
        $app->header = $response;
        $response->header("Server", "FoxBoot/v1.1");
        $response->header("Access-Control-Allow-Origin", '*');
        $response->header("Content-Type", "text/html; charset=utf-8");
        if ($request->server['request_uri'] == '/favicon.ico' || $request->server['path_info'] == '/favicon.ico') {
            return $response->end();
        }
        $GLOBALS['out_handler'] = function ($html) use ($response) {
            $response->write($html);
        };

        $filename = APP_DIR . DS . $app->server['request_uri'];
        if (file_exists($filename) && is_file($filename)) {
            $cache_time = 60 * 60;
            $modified_time = $app->server['http_if_modified_since'];
            if (strtotime($modified_time) + $cache_time > time()) {
                $app->response->status(304);
                return $app->response->end();
            }
            $info = \stat($filename);
            $modified_time = $info ? \date('D, d M Y H:i:s', $info['mtime']) . ' ' . \date_default_timezone_get() : '';
            //发送Last-Modified头标，设置文档的最后的更新日期。
            $app->response->header("Last-Modified", $modified_time);
            //发送Expires头标，设置当前缓存的文档过期时间，GMT格式，我们使用的是GMT+8时区
            $app->response->header("Expires", gmdate("D, d M Y H:i:s", time() + $cache_time) . " GMT");
            //发送Cache_Control头标，设置xx秒以后文档过时,可以代替Expires，如果同时出现，max-age优先。
            $app->response->header("Cache-Control", "max-age=$cache_time");
            if (ob_get_contents()) ob_end_clean();
            $ext = pathinfo($filename);
            $checkExt = ['shtml', 'html', 'htm'];
            if (in_array($ext['extension'], $checkExt)) {
                $file_data = file_get_contents($filename, true);
                $pattern = '/' . str_replace(array("<{", "}>"), array('\s*', '\s*'), '<\!\-\-#include\s*virtual\s*="(.+?)"\-\->') . '/i';
                $count = 1;
                while ($count != 0) {
                    preg_match($pattern, $file_data, $match);
                    $filename = APP_DIR . DS . $match[1];
                    if (is_file($filename)) {
                        $template = file_get_contents($filename, true);
                    } else {
                        $template = $filename . " file is not find!";
                    }
                    $file_data = preg_replace($pattern, $template, $file_data, 1, $count);
                }
                return $app->response->end($file_data);
            } else {
                if (isset($mimeTypeMap[$ext['extension']])) {
                    $app->response->header('Content-type', $mimeTypeMap[$ext]);
                } else {
                    $app->response->header('Content-type', "application/octet-stream");
                    $app->response->header('Content-Disposition', "attachment; filename='$filename'");
                }
                //Swoole大文件使用切块输出
                $fp = fopen($filename, 'r');
                $file_data = null;
                while (!feof($fp) && $app->response->write(fread($fp, 2048))) {
                }
                fclose($fp);
                return $app->response->end();
            }
        }
        // 启动一个服务
        $arr = explode('/', $app->server['request_uri']);
        $app->app_module = !empty($arr[1]) ? strtolower($arr[1]) : 'home';
        $app->app_controller = !empty($arr[2]) ? strtolower($arr[2]) : 'main';
        $app->app_action = !empty($arr[3]) ? strtolower($arr[3]) : 'index';
        $controller_name = str_replace("/", "\\", str_replace("//", "/", str_replace("\\\\", "\\", "app" . DS . $app->app_module . DS . 'controller' . DS . $app->app_controller . 'Control')));
        if (!empty($app->app_module)) if (!is_available_className($app->app_module)) return err("Err: Module '$app->app_module' is not correct!");
        if (!is_available_className($app->app_controller)) return err("Err: Controller '$controller_name' is not correct!");
        if (!class_exists($controller_name, true)) return err("Err: Controller '$controller_name' is not exists!");
        if (!method_exists($controller_name, $app->app_action)) return err("Err: Method '$app->app_action' of '$controller_name' is not exists!");
        $controller_obj = new $controller_name($app);
        $arr = explode('/', $app->server['request_uri']);
        try {
            call_user_func_array(array($controller_obj, $app->app_action), count($arr) > 4 ? array_slice($arr, 4) : array());
        } catch (Exception $e) {
            return $response->end();
        }
        if ($controller_obj->_auto_display) {
            $auto_tpl_name = (empty($app->app_module) ? '' : $app->app_module . DS) . $app->app_controller . '_' . $app->app_action . '.html';
            if (file_exists(APP_DIR . DS . 'app' . DS . 'view' . DS . $auto_tpl_name)) $controller_obj->display($auto_tpl_name);
        }
        return $response->end();
    }
}

initMimeTypeMap();
$run = new swoole();
$run->setting(array(
    'enable_static_handler' => true,
    'worker_num' => 2,    //开启两个worker进程
    'max_connection' => 256,
    'dispatch_mode' => 3,
    'package_max_length' => 20 * 1024 * 1024,
    'buffer_output_size' => 20 * 1024 * 1024,
    // 'document_root' => APP_DIR
));
$run->setPort(APP_PORT);
$run->start();

function initMimeTypeMap()
{
    global $mimeTypeMap;
    $mime_file = APP_DIR . '/lib/mime.types';
    if (!\is_file($mime_file)) {
        logs("$mime_file mime.type file not fond");
        return;
    }
    $items = \file($mime_file, \FILE_IGNORE_NEW_LINES | \FILE_SKIP_EMPTY_LINES);
    if (!\is_array($items)) {
        logs("get $mime_file mime.type content fail");
        return;
    }
    foreach ($items as $content) {
        if (\preg_match("/\s*(\S+)\s+(\S.+)/", $content, $match)) {
            $mime_type = $match[1];
            $workerman_file_extension_var = $match[2];
            $workerman_file_extension_array = \explode(' ', \substr($workerman_file_extension_var, 0, -1));
            foreach ($workerman_file_extension_array as $workerman_file_extension) {
                $mimeTypeMap[$workerman_file_extension] = $mime_type;
            }
        }
    }
}